<html>
<head><meta charset="utf-8"><title>MIR outlining · t-compiler/wg-mir-opt · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/index.html">t-compiler/wg-mir-opt</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html">MIR outlining</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="221255450"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221255450" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> cjgillot <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221255450">(Dec 30 2020 at 23:27)</a>:</h4>
<p>I am musing a design for <a href="https://github.com/rust-lang/rust/issues/77960">#77960</a> as a MIR transform. (Don't worry, this is a toy to learn MIR, nothing serious <span aria-label="big smile" class="emoji emoji-1f604" role="img" title="big smile">:big_smile:</span>.)<br>
The idea I have is essentially: to transform the function <code>f&lt;T&gt;</code></p>
<ol>
<li>take the original polymorphic MIR of <code>f</code> to define a helper function <code>f_impl</code>,</li>
<li><code>f_impl</code> takes all the operations done on the generic parameter <code>T</code> as function pointers on a adequately-sized buffer,</li>
<li>rewrite completely <code>f</code> to gather the proper function pointers and call <code>f_impl</code> with it.</li>
</ol>
<p>Of course, there is plenty of details to iron out. Steps 2 and 3 are a lot of MIR manipulations, which will require testing.<br>
Before going down this rabbit hole: is there even a way to create a new function <code>f_impl</code> out of thin air for step 1?<br>
I sure can write its MIR, but can I even assign it a <code>DefId</code> and manipulate it?<br>
(Step 3 will probably also require synthetizing new functions, but I'm not there yet.)</p>
<p>Thanks for your advice.</p>



<a name="221259011"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221259011" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221259011">(Dec 31 2020 at 00:35)</a>:</h4>
<p>No, that requires additional refactoring I think</p>



<a name="221259057"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221259057" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221259057">(Dec 31 2020 at 00:36)</a>:</h4>
<p>Maybe check out how <code>InstanceDef</code> is defined, we could add a variant for compiler-generated MIR bodies there, similar to existing shims and drop glue</p>



<a name="221273346"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221273346" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221273346">(Dec 31 2020 at 06:41)</a>:</h4>
<p>You could do something similar to promoted MIR.</p>



<a name="221305527"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221305527" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Joshua Nelson <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221305527">(Dec 31 2020 at 17:47)</a>:</h4>
<p>so if I understand correctly, steps 2 and 3 look something like transforming</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">f</span><span class="p">(</span><span class="n">val</span>: <span class="nc">impl</span><span class="w"> </span><span class="nb">AsRef</span><span class="o">&lt;</span><span class="kt">str</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">val</span><span class="p">.</span><span class="n">as_ref</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="n">val</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>into</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">f_impl</span><span class="p">(</span><span class="n">as_ref</span>: <span class="nc">fn</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">as_ref</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="n">val</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">f</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">f_impl</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="n">val</span><span class="p">.</span><span class="n">as_ref</span><span class="p">())</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>?</p>



<a name="221305603"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221305603" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Joshua Nelson <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221305603">(Dec 31 2020 at 17:48)</a>:</h4>
<p>there's a problem here which is that the closure is not a function pointer, it captures <code>val</code> - were you planning to pass that as a parameter to <code>f_impl</code>? And if so, how do you do that without making f_impl generic again?</p>



<a name="221305750"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221305750" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Joshua Nelson <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221305750">(Dec 31 2020 at 17:50)</a>:</h4>
<p>I guess you could take <code>*mut ()</code> for <code>val</code> and pass that to <code>as_ref</code>:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">f_impl</span><span class="p">(</span><span class="n">val</span>: <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="p">(),</span><span class="w"> </span><span class="n">as_ref</span>: <span class="nc">fn</span><span class="p">(</span><span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="p">())</span><span class="w"> </span>-&gt; <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">as_ref</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="n">val</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">f</span><span class="p">(</span><span class="n">val</span>: <span class="nc">impl</span><span class="w"> </span><span class="nb">AsRef</span><span class="o">&lt;</span><span class="kt">str</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">f_impl</span><span class="p">(</span><span class="o">&amp;</span><span class="n">val</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="o">|</span><span class="n">val</span>: <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="p">()</span><span class="o">|</span><span class="w"> </span><span class="n">transmute</span><span class="p">(</span><span class="n">val</span><span class="p">).</span><span class="n">as_ref</span><span class="p">())</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="221305883"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221305883" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Chase Wilson <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221305883">(Dec 31 2020 at 17:53)</a>:</h4>
<p>I don't think the suggested <code>fn()</code> method would work because of captured state, that'd probably end up making <em>more</em> IR for the compiler and LLVM to sift through, a more realistic strategy might be to emulate what users are already doing:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">f_impl</span><span class="p">(</span><span class="n">val</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">val</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>


<span class="k">fn</span> <span class="nf">f</span><span class="p">(</span><span class="n">val</span>: <span class="nc">impl</span><span class="w"> </span><span class="nb">AsRef</span><span class="o">&lt;</span><span class="kt">str</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">val</span><span class="p">.</span><span class="n">as_ref</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="n">f_impl</span><span class="p">(</span><span class="n">val</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Edit: I typed this up before the latter suggestion, that could work too</p>



<a name="221308067"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221308067" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221308067">(Dec 31 2020 at 18:33)</a>:</h4>
<p>I think we'd only do the split when the generic method calls are at the top of the function</p>



<a name="221326017"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221326017" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> cjgillot <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221326017">(Jan 01 2021 at 00:10)</a>:</h4>
<p><span class="user-mention silent" data-user-id="232545">Joshua Nelson</span> <a href="#narrow/stream/189540-t-compiler.2Fwg-mir-opt/topic/MIR.20outlining/near/221305750">said</a>:</p>
<blockquote>
<p>I guess you could take <code>*mut ()</code> for <code>val</code> and pass that to <code>as_ref</code>:</p>
<p><div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">f_impl</span><span class="p">(</span><span class="n">val</span>: <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="p">(),</span><span class="w"> </span><span class="n">as_ref</span>: <span class="nc">fn</span><span class="p">(</span><span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="p">())</span><span class="w"> </span>-&gt; <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">as_ref</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="n">val</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">f</span><span class="p">(</span><span class="n">val</span>: <span class="nc">impl</span><span class="w"> </span><span class="nb">AsRef</span><span class="o">&lt;</span><span class="kt">str</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">f_impl</span><span class="p">(</span><span class="o">&amp;</span><span class="n">val</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="o">|</span><span class="n">val</span>: <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="p">()</span><span class="o">|</span><span class="w"> </span><span class="n">transmute</span><span class="p">(</span><span class="n">val</span><span class="p">).</span><span class="n">as_ref</span><span class="p">())</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div><br>
</p>
</blockquote>
<p>Yes, this is essentially what I mean here. The point is to transform as close to the original MIR as possible.</p>



<a name="221326100"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221326100" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> cjgillot <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221326100">(Jan 01 2021 at 00:12)</a>:</h4>
<p>At least, this method works for stuff that can be represented by an <code>*mut u8</code>, ie things that are (mut?) references to <code>Sized</code> objects.<br>
The transform for non-<code>Sized</code> references and for values will come in a second time.</p>



<a name="221569302"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221569302" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Erick Tryzelaar <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221569302">(Jan 04 2021 at 19:32)</a>:</h4>
<p>This could be a great feature, and I think it'd be totally worth doing. We did some analysis a few years ago on fuchsia, and found a lot of code bloat was coming from generic functions like this, and so I pitched that idea to <span class="user-mention" data-user-id="116009">@nikomatsakis</span> and <span class="user-mention" data-user-id="116883">@tmandry</span> rustconf before last. We did some optimizations by hand for the easily identified hotspots, but it's such a prevalent issue that having this done automatically would really simplify things At the time, we had thought it'd be pretty reasonable to just split off the generic methods at the top of the function, since that's the most common case, and would probably lead to a lot of big wins</p>



<a name="221569813"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221569813" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> lqd <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221569813">(Jan 04 2021 at 19:36)</a>:</h4>
<p>there's also been recent work on outlining in LLVM (from Apple IIRC) with a more general and usable design than the previous attempts</p>



<a name="221575117"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/MIR%20outlining/near/221575117" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/MIR.20outlining.html#221575117">(Jan 04 2021 at 20:18)</a>:</h4>
<p>Would be great to get this, even if just for a few well-known traits.  <code>AsRef&lt;Path&gt;</code> seems particularly likely -- I <a href="https://github.com/rust-lang/rust/pull/58530">did it manually</a> for a few <code>fs</code> methods, for example.</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>